package ru.amse.jsynchro.net.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.OutputStream;
import java.net.Socket;

import ru.amse.jsynchro.kernel.DirectoryTree;
import ru.amse.jsynchro.kernel.IDirectoryTree;
import ru.amse.jsynchro.logging.ILogger;
import ru.amse.jsynchro.net.Command;
import ru.amse.jsynchro.net.stream.LimitedInputStream;
import ru.amse.jsynchro.net.stream.LimitedOutputStream;
import ru.amse.jsynchro.net.stream.ProtocolInputStream;
import ru.amse.jsynchro.net.stream.ProtocolOutputStream;

public class ServerThread extends Thread {
    protected ObjectOutput oout;
    protected ObjectInput oin;
    protected String myLocalRoot;
    protected OutputStream socketOut;
    protected InputStream socketIn;
    protected Socket socket;
    protected InputStream fis;
    protected OutputStream fos;
    protected static int myThreadNumber = 0;
    protected ILogger logger;
    private String path;
    
    public ServerThread(Socket socket, int threadNumber, ILogger logger) {
        this.socket = socket;
        myThreadNumber = threadNumber;
        this.logger = logger;
    }
    
    protected boolean handleClientCommand(Command cmd) throws IOException, ClassNotFoundException {
        switch (cmd.getType()) {
        case Command.GET_TREE_ROOT: {
            oout.writeObject(myLocalRoot);
            break;
        }
        case Command.GET_TREE: {
            String root = (String) oin.readObject();
            logger.info("root: " + root);
            IDirectoryTree tree = new DirectoryTree(new File(root), null);
            oout.writeObject(tree);
            break;
        }
        case Command.END: {
            socket.close();
            return false;
        }
        case Command.GET_FILE: {
            path = (String) oin.readObject();
            logger.info("path: " + path);
            File file = new File(path);
            fis = new FileInputStream(file);
            InputStream in = new LimitedInputStream(fis, file.length());
            OutputStream out = new ProtocolOutputStream(socketOut, file.length(), oin);
            int c = 0;
            while ((c = in.read()) >= 0) {
                out.write(c);
            }
            fis.close();
//            byte[] buf = new byte[1024];
//            int c = 0;
//            while ((c = fis.read(buf)) == 1024) {
//                socketOut.write(buf);
//            }
//            if (c > 0) {
//                socketOut.write(buf, 0, c); 
//            }
            logger.info("finished reading file");
            break;
        }
        case Command.WRITE_FILE: {
            path = (String) oin.readObject();
            logger.info("path:" + path);
            Long length = (Long) oin.readObject();
            oout.writeObject("ok");
            fos = new FileOutputStream(path);
            
            InputStream in = new ProtocolInputStream(socketIn, length, oout);
            OutputStream out = new LimitedOutputStream(fos, length);
            int c = 0;
            while ((c = in.read()) >= 0) {
                out.write(c);
            }
            fos.close();
            break;
        }
        case Command.MAKE_DIRECTORY: {
            path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            f.mkdir();
            break;
        }
        case Command.CLOSE_INPUT_STREAM: {
            logger.info("closing in: " + path);
//            fis.close();
            break;
        }
        case Command.CLOSE_OUTPUT_STREAM: {
            logger.info("closing out: " + path);
//            fos.close();
            break;
        }
        case Command.LIST_FILES: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            File[] files = f.listFiles();
            oout.writeObject(files);
            break;
        } 
        case Command.DELETE_FILE: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            if (f.delete()) {
                oout.writeObject("ok");
            } else {
                oout.writeObject("not_ok");
            }
            break;
        }
        case Command.GET_FILE_LENGTH: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            oout.writeObject(new Long(f.length()));
            break;
        }
        case Command.IS_DIRECTORY: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            oout.writeObject(Boolean.valueOf(f.isDirectory()));
            break;
        }
        case Command.ATTR_EXECUTE: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            if (f.canExecute()) {
                f.setExecutable(false);
            } else {
                f.setExecutable(true);
            }
            break;
        }
        case Command.ATTR_READ: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            if (f.canRead()) {
                f.setReadable(false);
            } else {
                f.setReadable(true);
            }
            break;
        }
        case Command.ATTR_WRITE: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            if (f.canWrite()) {
                f.setWritable(false);
            } else {
                f.setWritable(true);
            }
            break;
        }
        case Command.ATTR_HIDDEN: {
            String path = (String) oin.readObject();
            logger.info("path: " + path);
            File f = new File(path);
            if (f.isHidden()) {
//                f.(false);
            } else {
//                f.setExecutable(true);
            }
            break;
        }
        default: {
            throw new AssertionError("error query");
        }
        }
        return true;
    }
}
